
package ai_game;

import entity.AI_Agent;
import entity.Enemy1;
import entity.GameObject;
import entity.Player;
import entity.Wall;
import java.util.ArrayList;
import java.util.Map;
import org.newdawn.slick.Animation;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Circle;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.geom.Vector2f;
import physics.PhysicsEngine;
import sprites.EntityAnimationInstance;
import sprites.SpriteLoader;
import tiling.AreaMap;

/**
 *
 * @author ant
 */
public class Game extends org.newdawn.slick.BasicGame
{
    public static final float physicTickLengthSeconds = (float) 0.033;
    public static final int cameraBorder = 150;
    public boolean debug = true;
    
    AreaMap map;
    Rectangle camera = new Rectangle(0, 0, 640, 480);
    Input input;
    Player player;
    SpriteLoader spriteLoader;
    ArrayList<AI_Agent> enemies = new ArrayList<>();
    ArrayList<GameObject> gameObjects = new ArrayList<>();
    
    public PhysicsEngine physicsEngine = new PhysicsEngine(physicTickLengthSeconds);
    float physicsTimeAccumulated = 0;
    
    public Game(String name)
    {       
        super(name);
    }
    
    @Override
    public void init(GameContainer gc) throws SlickException
    {
        spriteLoader = new SpriteLoader();
        
        input  = gc.getInput();
        map = new AreaMap();
        Vector2f playerStart = map.getPlayerStart();
        player = new Player(playerStart);

        
        
        player.animation = spriteLoader.getAnimation("alice");
        physicsEngine.addObject(player);
        
        for(Rectangle rect : map.getWalls())
        {
            physicsEngine.addObject(new Wall(rect));
            
        }
        double i=0;
        for(Vector2f pos : map.getEnemyStarts())
        {
            Enemy1 enemy = new Enemy1();
            enemy.pos = pos.copy();
            enemy.animation = spriteLoader.getAnimation("chen");
            enemy.collisionShape = new Circle(pos.y, pos.y, 16);
            
            //this should give the enemies different headings to show that radar gets distance and heading
            i+=90;
            enemy.setInitialState(Math.toRadians(i));
            
            enemies.add(enemy);
            gameObjects.add(enemy);
            physicsEngine.addObject(enemy);
        }
    }

    @Override
    public void update(GameContainer gc, int i) throws SlickException
    {
        handleInput();
        player.sense(gameObjects); //this is for assignment 1 and can be removed, or possibly modified to be used as a radar for doing things like hearing things around you -- spidy-sense type of thing?
        player.update();
        
        //update game logic/AI
        for(AI_Agent agent : enemies)
        {
            agent.sense();
            agent.think();
            agent.act();
        }
        
        for(GameObject go : gameObjects)
        {
            go.update();
        }
        
        //update physics
        physicsTimeAccumulated += i/1000.0;
        while(physicsTimeAccumulated >= physicTickLengthSeconds)
        {
            physicsEngine.update();
            physicsTimeAccumulated -= physicTickLengthSeconds;
        }
        
    }

    @Override
    public void render(GameContainer gc, Graphics grphcs) throws SlickException
    {
        moveCamera();
        
        //render map (background)
        map.render(camera);

        player.render(camera);
        
        //draw sensor stuff for assignment 1
        player.a1render(camera, grphcs);
        
        
        grphcs.drawString(player.pos.toString(), 10, 30);
        grphcs.drawString(player.vel.toString(), 10, 50);
        
        
        //grphcs.drawAnimation(player.animation, 200, 200);
        
        //render other game objects
        for(GameObject go : gameObjects)
        {
            go.render(camera);
        }
        physicsEngine.renderDebugShapes(camera, grphcs);
        
        
    }
        
    void handleInput()
    {
        boolean up   = input.isKeyDown(Input.KEY_S);
        boolean down = input.isKeyDown(Input.KEY_W);
        boolean left = input.isKeyDown(Input.KEY_A);
        boolean right= input.isKeyDown(Input.KEY_D);
        Vector2f dir = new Vector2f();
        if(down && !up) dir.y = -1;
        else if(up && !down) dir.y = 1;
        
        if(left && !right) dir.x = -1;
        else if(right && !left) dir.x = 1;
        
        
        
        //tank controls for Assignment1
        if(input.isKeyDown(Input.KEY_J)){
            //rotate left
            player.headingRadians -= Math.toRadians(3);
            if(player.headingRadians<0)player.headingRadians=2*Math.PI;
        }
        if(input.isKeyDown(Input.KEY_L)){
            //rotate right
            player.headingRadians += Math.toRadians(3);
            if(player.headingRadians>2*Math.PI)player.headingRadians=0;
        }
        if(input.isKeyDown(Input.KEY_I)){
            dir.x=0; dir.y=0;
            //move forward
            dir.y = (float)Math.sin(Math.toRadians(Math.toDegrees(player.headingRadians)));
            dir.x = (float)Math.cos(Math.toRadians(Math.toDegrees(player.headingRadians)));
        }
        if(input.isKeyDown(Input.KEY_K)){
            dir.x=0; dir.y=0;
            //move backward
            dir.y = -(float)Math.sin(Math.toRadians(Math.toDegrees(player.headingRadians)));
            dir.x = -(float)Math.cos(Math.toRadians(Math.toDegrees(player.headingRadians)));
        }
        
        //if using orthagonal movement, set heading as well
        if(up || down || left || right)
            player.setDirection(dir);
        else
            player.setDirection(dir,false);
    }   
    
        private void moveCamera()
    {
        if(player.pos.x - camera.getX() < cameraBorder)
        {
            camera.setX(player.pos.x - cameraBorder);
        }
        if(player.pos.x - camera.getX() > camera.getWidth() - cameraBorder)
        {
            camera.setX(player.pos.x + cameraBorder - camera.getWidth());
        }

        if(player.pos.y - camera.getY() < cameraBorder)
        {
            camera.setY(player.pos.y - cameraBorder);
        }
        if(player.pos.y - camera.getY() > camera.getHeight() - cameraBorder)
        {
            camera.setY(player.pos.y + cameraBorder - camera.getHeight());
        }    
    }

}
